﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ItemsViewer;

namespace ItemsViewerDemo.ViewModels
{
    /// <summary>
    /// Main View Model.
    /// </summary>
    public class MainViewModel : ProgressViewModel
    {
        /// <summary>
        /// The Collection of SortType.
        /// </summary>
        private ObservableCollection<SortType> sortTypes;

        /// <summary>
        /// The collection of pictures.
        /// </summary>
        private FilterAnimatedListCollectionView picturesView;

        /// <summary>
        /// Search value.
        /// </summary>
        private string searchValue;

        /// <summary>
        /// Size value.
        /// </summary>
        private double sizeValue;

        /// <summary>
        /// The scroll item value;
        /// </summary>
        private string scrollItemValue;

        /// <summary>
        /// The random number generator.
        /// </summary>
        private Random rdn;

        /// <summary>
        ///  Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            this.SearchValue = string.Empty;
            this.SizeValue = 0;
            this.ScrollItemValue = "0";
            this.rdn = new Random();

            // Load Data.
            this.LoadData();

            // Define commands
            this.ClearAllFilterCommand = new Command((s, e) => this.OnClearAllFilter());
            this.SearchCommand = new Command((s, e) => this.OnSearch());
            this.ScrollItemCommand = new Command((s, e) => this.OnScrollItem());
            this.AddItemCommand = new Command((s, e) => this.OnAddItem());
            this.RemoveItemCommand = new Command((s, e) => this.OnRemoveItem());
        }

        /// <summary>
        /// Gets or sets SortTypes.
        /// </summary>
        public ObservableCollection<SortType> SortTypes
        {
            get
            {
                return this.sortTypes;
            }

            set
            {
                this.sortTypes = value;
                OnPropertyChanged(() => this.SortTypes);
            }
        }

        /// <summary>
        /// Gets or sets PicturesView.
        /// </summary>
        public FilterAnimatedListCollectionView PicturesView
        {
            get
            {
                return this.picturesView;
            }

            set
            {
                this.picturesView = value;
                OnPropertyChanged(() => this.PicturesView);
            }
        }

        /// <summary>
        /// Gets or sets SearchValue.
        /// </summary>
        public string SearchValue
        {
            get
            {
                return this.searchValue;
            }

            set
            {
                this.searchValue = value;
                OnPropertyChanged(() => this.SearchValue);
            }
        }

        /// <summary>
        /// Gets or sets SearchValue.
        /// </summary>
        public double SizeValue
        {
            get
            {
                return this.sizeValue;
            }

            set
            {
                this.sizeValue = value;
                OnPropertyChanged(() => this.SizeValue);
                if (this.PicturesView != null)
                {
                    this.PicturesView.RefreshFilterAnimated();
                }
            }
        }

        /// <summary>
        /// Gets MaximumSizeValue.
        /// </summary>
        public double MaximumSizeValue
        {
            get
            {
                if (this.PicturesView != null)
                {
                    return (this.PicturesView.SourceCollection as ObservableCollection<Picture>).Max(x => x.Size);
                }
                else
                {
                    return 100;
                }
            }
        }

        /// <summary>
        /// Gets CountItem.
        /// </summary>
        public int CountItem
        {
            get
            {
                if (this.PicturesView != null)
                {
                    return this.PicturesView.Count;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// Gets or sets ScrollItemValue.
        /// </summary>
        public string ScrollItemValue
        {
            get
            {
                return this.scrollItemValue;
            }

            set
            {
                this.scrollItemValue = value;
                OnPropertyChanged(() => this.ScrollItemValue);
            }
        }

        /// <summary>
        /// Gets ClearAllFilterCommand.
        /// </summary>
        public ICommand ClearAllFilterCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets SearchCommand.
        /// </summary>
        public ICommand SearchCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets ScrollCommand.
        /// </summary>
        public ICommand ScrollItemCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets AddItemCommand.
        /// </summary>
        public ICommand AddItemCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets RemoveItemCommand.
        /// </summary>
        public ICommand RemoveItemCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Load Data.
        /// </summary>
        private void LoadData()
        {
            // Init SortTypes.
            var sortTypes = new List<SortType>();
            var nameSort = new SortType() { Name = "Name" };
            var sizeSort = new SortType() { Name = "Size" };
            nameSort.PropertyChanged += this.SortPropertyChanged;
            sizeSort.PropertyChanged += this.SortPropertyChanged;
            sortTypes.Add(nameSort);
            sortTypes.Add(sizeSort);
            this.SortTypes = new ObservableCollection<SortType>(sortTypes);

            // Load Async ImageList
            Task task = Task.Factory.StartNew(() =>
            {
                try
                {
                    this.IsBusy = true;
                    ObservableCollection<Picture> imageList = new ObservableCollection<Picture>(GetImageList());
                    this.DispatcherBeginInvoke((Action)(() =>
                    {
                        this.PicturesView = new FilterAnimatedListCollectionView(imageList);
                        this.PicturesView.FilterAnimated = item =>
                        {
                            Picture picture = item as Picture;
                            return picture.Name.Contains(SearchValue) && picture.Size >= SizeValue;
                        };
                        this.PicturesView.FilterAnimatedCompleted += (s, e) =>
                        {
                            OnPropertyChanged(() => this.CountItem);
                        };
                    }));
                }
                finally
                {
                    this.IsBusy = false;
                }
            });
        }

        /// <summary>
        /// On Sort property changed, add or remove SortDescription.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The PropertyChangedEventArgs.</param>
        private void SortPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            var s = sender as SortType;
            if (s.IsChecked)
            {
                var sortDescription = new SortDescription(s.Name, ListSortDirection.Ascending);
                this.PicturesView.SortDescriptions.Add(sortDescription);
            }
            else
            {
                var sortDescription = (from sd in this.PicturesView.SortDescriptions where sd.PropertyName == s.Name select sd).SingleOrDefault();
                if (sortDescription != null)
                {
                    this.PicturesView.SortDescriptions.Remove(sortDescription);
                }
            }
        }

        /// <summary>
        /// Clear all filter.
        /// </summary>
        private void OnClearAllFilter()
        {
            this.SearchValue = string.Empty;
            this.SizeValue = 0;
            this.ScrollItemValue = string.Empty;
            if (this.PicturesView != null)
            {
                this.PicturesView.SortDescriptions.Clear();
            }

            OnPropertyChanged(() => this.CountItem);
        }

        /// <summary>
        /// Search and refresh filter.
        /// </summary>
        private void OnSearch()
        {
            if (this.PicturesView != null)
            {
                this.PicturesView.RefreshFilterAnimated();
            }
        }

        /// <summary>
        /// Scroll to item.
        /// </summary>
        private void OnScrollItem()
        {
            try
            {
                var scrollItem = Convert.ToInt32(this.ScrollItemValue);
                if (scrollItem <= this.CountItem)
                {
                    this.PicturesView.MoveCurrentToPosition(scrollItem);
                }
            }
            catch (InvalidCastException)
            {
                // todo
            }
        }

        /// <summary>
        /// On Add Item.
        /// </summary>
        private void OnAddItem()
        {
            this.PicturesView.MoveCurrentToPosition(0);
            var index = Random(0, this.CountItem - 1);
            var picture = (this.PicturesView.SourceCollection as ObservableCollection<Picture>)[index];

            if (picture != null)
            {
                var newPicture = new Picture() { Name = picture.Name, Url = picture.Url, Size = picture.Size };
                (this.PicturesView.SourceCollection as ObservableCollection<Picture>).Insert(0, picture);
                OnPropertyChanged(() => this.CountItem);
            }
        }

        /// <summary>
        /// On Remove Item.
        /// </summary>
        private void OnRemoveItem()
        {
            if (this.CountItem > 0)
            {
                this.PicturesView.MoveCurrentToPosition(0);
                this.PicturesView.RemoveAt(0);
            }
        }

        /// <summary>
        /// Get random number.
        /// </summary>
        /// <param name="min">Min value.</param>
        /// <param name="max">Maxy value.</param>
        /// <returns>Random number</returns>
        private int Random(int min, int max)
        {
            return rdn.Next(min, max);
        }


        /// <summary>
        /// Return Get Image list from ressource.
        /// </summary>
        /// <returns>Return Image list.</returns>
        private static List<Picture> GetImageList()
        {
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
            System.Globalization.CultureInfo culture = Thread.CurrentThread.CurrentCulture;
            string resourceName = asm.GetName().Name + ".g";
            System.Resources.ResourceManager rm = new System.Resources.ResourceManager(resourceName, asm);
            System.Resources.ResourceSet resourceSet = rm.GetResourceSet(culture, true, true);
            List<Picture> resources = new List<Picture>();
            foreach (DictionaryEntry resource in resourceSet)
            {
                if (((string)resource.Key).Contains(".jpg"))
                {
                    var mb = ((System.IO.UnmanagedMemoryStream)resource.Value).Length / 1024f;
                    resources.Add(new Picture() { Url = (string)resource.Key, Name = Regex.Split((string)resource.Key, "/")[1], Size = Math.Round(mb, 2) });
                }
            }

            rm.ReleaseAllResources();
            return resources;
        }
    }
}
